Lenguaje Python 3 Módulo 12

Se estudian en el módulo 12 de Python lo referente a la clasificación de datos mediante los métodos K-medias y Clusterización Jerárquica.

Método K-medias

El algoritmo K-medias propuesto por MacQueen en el año 1967 es un algoritmo que permite descubrir agrupamientos en conjuntos de datos.

K-medias es un método que tiene como objetivo generar una partición de un conjunto de n observaciones en k grupos. Cada grupo está representado por el promedio de los puntos que lo componen. El representante de cada grupo se denomina centroide. La cantidad de grupos a descubrir, k, es un parámetro que se debe fijar al ajecutar el método.

El método de clasificación (clustering en inglés) comienza a partir de k centroides ubicados de forma aleatoria, y asigna cada observación al centroide más “cercano”. La forma de determinar esta “cercanía” podría depender del tipo de datos.

Es posible por ello establecer una “distancia” equivalente/adecuada en el plano o espacio (vectorial) al que pertenecen los datos. Es por ello, que a pesar de que la distancia euclidiana es por definición la que se supone, pueden determinarse métodos externos que permitan calcular una “distancia” que sea más adecuada al tipo de los datos.

Después de asignar los centroides, estos se deben ir moviendoa a una ubicación que sea el promedio de todos los datos asignados a este centroide. Luego se reptite el algoritmo reasignando los puntos de acuerdo a las nuevas posiciones de los centroides. Los datos no se cambian, se corrige el centroide. Se busca que los datos asociados a un centroide estén lo mas cercanos a este centroida además que los grupos estén lo más separados entre ellos.

Detalle algorítmico.

El objetivo de K-medias es agrupar a las observaciones de forma tal que todas las que se encuentren en el mismo grupo sean lo más cercanas (semejantes) entre sí y que las pertenecientes a grupos distintos sean lo más distantes (distintas) entre sí. Las medidas de distancia, como se indicó anteriormente, suele ser la euclídea, y son utilizadas para medir la distancia. Una medida para indicar cuán bien los centroides representan a los miembros de su grupo es la suma de los errores al cuadrado.

Y para ello en K-medias, cada iteración intenta reducir el valor de este error. La medida euclidiana consiste en la sumatoria de las distancias al cuadrado de cada observación con el “centroide” propuesto con respecto a determinado grupo.

El algoritmo podría dar resultados mejores en algunas “corridas” que en otras debido a la aletoriedad del inicio. Es común que los índices obtenidos para los grupos en diferentes corridas se intercambien (numéricamente) y los datos queden agrupados de la misma forma. Además el método podría no ser óptimo.

import os
import pandas as pd
import matplotlib.pyplot as plt
from   sklearn.decomposition import PCA
from   sklearn.datasets import make_blobs
from   sklearn.cluster import KMeans
import numpy as np
from   math import pi

import mglearn


# Plotea un ejemplo de ejecución del algoritmo k-medias
mglearn.plots.plot_kmeans_algorithm()
plt.show()

plt.close()

# Plotea las fonteras de clases (diagrama de Voronoi)
mglearn.plots.plot_kmeans_boundaries()
plt.show()

plt.close()
# Un ejemplo con datos sinteticos

# Ejemplo 1. Datos simlados en 2 variables
X, y = make_blobs(random_state=1)
print(X[0:10]) # Datos
## [[ -0.79415228   2.10495117]
##  [ -9.15155186  -4.81286449]
##  [-11.44182631  -4.45781441]
##  [ -9.76761777  -3.19133737]
##  [ -4.53655648  -8.40186288]
##  [ -6.26302115  -8.10666081]
##  [ -6.38481234  -8.4730297 ]
##  [ -9.20490564  -4.57687928]
##  [ -2.76017908   5.55121358]
##  [ -1.17104176   4.33091816]]
print(y) # Cluster

# Construye un modelo k-medias
## [0 1 1 1 2 2 2 1 0 0 1 1 2 0 2 2 2 0 1 1 2 1 2 0 1 2 2 0 0 2 0 0 2 0 1 2 1
##  1 1 2 2 1 0 1 1 2 0 0 0 0 1 2 2 2 0 2 1 1 0 0 1 2 2 1 1 2 0 2 0 1 1 1 2 0
##  0 1 2 2 0 1 0 1 1 2 0 0 0 0 1 0 2 0 0 1 1 2 2 0 2 0]
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)

# Cluster al que pertenece al que asigna k-medias (dos formas de hacerlo)
## KMeans(n_clusters=3)
print("Cluster al que pertenece cada individuo:\n{}".format(kmeans.labels_))
## Cluster al que pertenece cada individuo:
## [0 2 2 2 1 1 1 2 0 0 2 2 1 0 1 1 1 0 2 2 1 2 1 0 2 1 1 0 0 1 0 0 1 0 2 1 2
##  2 2 1 1 2 0 2 2 1 0 0 0 0 2 1 1 1 0 1 2 2 0 0 2 1 1 2 2 1 0 1 0 2 2 2 1 0
##  0 2 1 1 0 2 0 2 2 1 0 0 0 0 2 0 1 0 0 2 2 1 1 0 1 0]
print(kmeans.predict(X))


# Plotea el resultado
# Es posible directamente porque solo hay dos variables
## [0 2 2 2 1 1 1 2 0 0 2 2 1 0 1 1 1 0 2 2 1 2 1 0 2 1 1 0 0 1 0 0 1 0 2 1 2
##  2 2 1 1 2 0 2 2 1 0 0 0 0 2 1 1 1 0 1 2 2 0 0 2 1 1 2 2 1 0 1 0 2 2 2 1 0
##  0 2 1 1 0 2 0 2 2 1 0 0 0 0 2 0 1 0 0 2 2 1 1 0 1 0]
null=mglearn.discrete_scatter(X[:, 0], X[:, 1], kmeans.labels_, markers='o')
null=mglearn.discrete_scatter(  kmeans.cluster_centers_[:, 0], 
                           kmeans.cluster_centers_[:, 1], 
                           [0, 1, 2],
                           markers='^', markeredgewidth=2)
plt.show()

plt.close()


mglearn.plots.plot_kmeans_boundaries()
plt.show()

plt.close()
# Ejemplo 2. Datos de Estudiantes
#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
#os.chdir("./Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploEstudiantes.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
##         Matematicas  Ciencias  Espanol  Historia  EdFisica
## Lucia           7.0       6.5      9.2       8.6       8.0
## Pedro           7.5       9.4      7.3       7.0       7.0
## Ines            7.6       9.2      8.0       8.0       7.5
## Luis            5.0       6.5      6.5       7.0       9.0
## Andres          6.0       6.0      7.8       8.9       7.3
## Ana             7.8       9.6      7.7       8.0       6.5
## Carlos          6.3       6.4      8.2       9.0       7.2
## Jose            7.9       9.7      7.5       8.0       6.0
## Sonia           6.0       6.0      6.5       5.5       8.7
## Maria           6.8       7.2      8.7       9.0       7.0
print(datos.head())
##         Matematicas  Ciencias  Espanol  Historia  EdFisica
## Lucia           7.0       6.5      9.2       8.6       8.0
## Pedro           7.5       9.4      7.3       7.0       7.0
## Ines            7.6       9.2      8.0       8.0       7.5
## Luis            5.0       6.5      6.5       7.0       9.0
## Andres          6.0       6.0      7.8       8.9       7.3
print(datos.shape)


# Ejecuta k-medias con 3 clusters
## (10, 5)
kmedias = KMeans(n_clusters=3)
kmedias.fit(datos)
## KMeans(n_clusters=3)
print(kmedias.predict(datos))
## [0 1 1 2 0 1 0 1 2 0]
centros = np.array(kmedias.cluster_centers_)
print(centros)
# Plotea Centro 1
## [[6.525 6.525 8.475 8.875 7.375]
##  [7.7   9.475 7.625 7.75  6.75 ]
##  [5.5   6.25  6.5   6.25  8.85 ]]
c1 = centros[:1, :]
print(c1)
## [[6.525 6.525 8.475 8.875 7.375]]
y=c1.tolist()[0]
print(y)
## [6.525, 6.525, 8.475, 8.875, 7.375]
N = len(y)
print(N)
## 5
x = range(N)
print(x)
## range(0, 5)
width = 1/1.5
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()

plt.close()

# Plotea Centro 2
c2 = centros[1:2, :]
y=c2.tolist()[0]
N = len(y)
x = range(N)
width = 1/1.5
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()

plt.close()

# Plotea Centro 3
c3 = centros[2:3, :]
y=c3.tolist()[0]
N = len(y)
x = range(N)
width = 1/1.5
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()

plt.close()
# LOS TRES JUNTOS
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y  = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)

# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)

# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)

#Todos juntos
plt.show()

plt.close()
# RADAR PLOT para interpretar
# ===========================

datos
##         Matematicas  Ciencias  Espanol  Historia  EdFisica
## Lucia           7.0       6.5      9.2       8.6       8.0
## Pedro           7.5       9.4      7.3       7.0       7.0
## Ines            7.6       9.2      8.0       8.0       7.5
## Luis            5.0       6.5      6.5       7.0       9.0
## Andres          6.0       6.0      7.8       8.9       7.3
## Ana             7.8       9.6      7.7       8.0       6.5
## Carlos          6.3       6.4      8.2       9.0       7.2
## Jose            7.9       9.7      7.5       8.0       6.0
## Sonia           6.0       6.0      6.5       5.5       8.7
## Maria           6.8       7.2      8.7       9.0       7.0
centros
## array([[6.525, 6.525, 8.475, 8.875, 7.375],
##        [7.7  , 9.475, 7.625, 7.75 , 6.75 ],
##        [5.5  , 6.25 , 6.5  , 6.25 , 8.85 ]])
centros_trans = centros.T
centros_trans
## array([[6.525, 7.7  , 5.5  ],
##        [6.525, 9.475, 6.25 ],
##        [8.475, 7.625, 6.5  ],
##        [8.875, 7.75 , 6.25 ],
##        [7.375, 6.75 , 8.85 ]])
V1 = centros_trans[:1,:]
print(V1)
## [[6.525 7.7   5.5  ]]
V1=V1.tolist()[0]
print(V1)
## [6.525, 7.7, 5.5]
V2 = centros_trans[1:2,:]
print(V2)
## [[6.525 9.475 6.25 ]]
V2=V2.tolist()[0]
print(V2)
## [6.525, 9.475, 6.25]
V3 = centros_trans[2:3,:]
print(V3)
## [[8.475 7.625 6.5  ]]
V3=V3.tolist()[0]
print(V3)
## [8.475, 7.625, 6.5]
V4 = centros_trans[3:4,:]
print(V4)
## [[8.875 7.75  6.25 ]]
V4=V4.tolist()[0]
print(V4)
## [8.875, 7.75, 6.25]
V5 = centros_trans[4:5,:]
print(V5)
## [[7.375 6.75  8.85 ]]
V5=V5.tolist()[0]
print(V5)

# Datos para el Radar Plot
## [7.375, 6.75, 8.85]
df = pd.DataFrame({
'grupo': ['Cluster-1','Cluster-2','Cluster-3'],
'Matematicas': V1,
'Ciencias': V2,
'Espanol': V3,
'Historia': V4,
'EdFisica': V5
})

print(df)

#Otra forma de hacer lo mismo:
##        grupo  Matematicas  Ciencias  Espanol  Historia  EdFisica
## 0  Cluster-1        6.525     6.525    8.475     8.875     7.375
## 1  Cluster-2        7.700     9.475    7.625     7.750     6.750
## 2  Cluster-3        5.500     6.250    6.500     6.250     8.850
df = pd.DataFrame()
for i in range(datos.shape[1]):
    df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)

df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)

# Variables y Número de Variables
##    Matematicas  Ciencias  Espanol  Historia  EdFisica      grupo
## 0        6.525     6.525    8.475     8.875     7.375  Cluster-1
## 1        7.700     9.475    7.625     7.750     6.750  Cluster-2
## 2        5.500     6.250    6.500     6.250     8.850  Cluster-3
variables=list(df)[0:5]
print(variables)
## ['Matematicas', 'Ciencias', 'Espanol', 'Historia', 'EdFisica']
N = len(variables)
print(N)
 
# Ángulo de los ejes 
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
 
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
 
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
 
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
 
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)

# Plotea cada cluster (grupo) = una línea de datos
 
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
 
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()
# Los dibuja sobre el plano principal los clusters de k-medias
pca = PCA(n_components=2)
componentes = pca.fit_transform(datos)
componentes
## array([[-0.76471745, -1.5817637 ],
##        [ 1.66887794,  1.39196556],
##        [ 1.57822841,  0.29949595],
##        [-2.60701317,  1.32020402],
##        [-1.43877557, -1.33566867],
##        [ 2.34790534,  0.3880845 ],
##        [-0.89372557, -1.51890124],
##        [ 2.64984571,  0.4254636 ],
##        [-2.62959083,  2.18339513],
##        [ 0.08896518, -1.57227516]])
print(datos.shape)
## (10, 5)
print(componentes.shape)
## (10, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(datos))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()

plt.close()
# Ejemplo 3. Datos de Iris
iris = pd.read_csv('../Datos/iris.csv',delimiter=';',decimal=".")
print(iris)
##      s.largo  s.ancho  p.largo  p.ancho       tipo
## 0        5.1      3.5      1.4      0.2     setosa
## 1        4.9      3.0      1.4      0.2     setosa
## 2        4.7      3.2      1.3      0.2     setosa
## 3        4.6      3.1      1.5      0.2     setosa
## 4        5.0      3.6      1.4      0.2     setosa
## ..       ...      ...      ...      ...        ...
## 145      6.7      3.0      5.2      2.3  virginica
## 146      6.3      2.5      5.0      1.9  virginica
## 147      6.5      3.0      5.2      2.0  virginica
## 148      6.2      3.4      5.4      2.3  virginica
## 149      5.9      3.0      5.1      1.8  virginica
## 
## [150 rows x 5 columns]
iris.head()
##    s.largo  s.ancho  p.largo  p.ancho    tipo
## 0      5.1      3.5      1.4      0.2  setosa
## 1      4.9      3.0      1.4      0.2  setosa
## 2      4.7      3.2      1.3      0.2  setosa
## 3      4.6      3.1      1.5      0.2  setosa
## 4      5.0      3.6      1.4      0.2  setosa
iris.shape

# Ejecuta k-medias con 3 clusters
## (150, 5)
kmedias = KMeans(n_clusters=3)
iris_tempo=iris.iloc[:,:4]
iris_tempo
##      s.largo  s.ancho  p.largo  p.ancho
## 0        5.1      3.5      1.4      0.2
## 1        4.9      3.0      1.4      0.2
## 2        4.7      3.2      1.3      0.2
## 3        4.6      3.1      1.5      0.2
## 4        5.0      3.6      1.4      0.2
## ..       ...      ...      ...      ...
## 145      6.7      3.0      5.2      2.3
## 146      6.3      2.5      5.0      1.9
## 147      6.5      3.0      5.2      2.0
## 148      6.2      3.4      5.4      2.3
## 149      5.9      3.0      5.1      1.8
## 
## [150 rows x 4 columns]
kmedias.fit(iris_tempo)
## KMeans(n_clusters=3)
print(kmedias.predict(iris_tempo))
## [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
##  0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 2 2 2 0 2 2 2 2
##  2 2 0 0 2 2 2 2 0 2 0 2 0 2 2 0 0 2 2 2 2 2 0 2 2 2 2 0 2 2 2 0 2 2 2 0 2
##  2 0]
centros = np.array(kmedias.cluster_centers_)
print(centros) 

# Los dibuja sobre el plano principal
## [[5.9016129  2.7483871  4.39354839 1.43387097]
##  [5.006      3.418      1.464      0.244     ]
##  [6.85       3.07368421 5.74210526 2.07105263]]
pca = PCA(n_components=2)
componentes = pca.fit_transform(iris_tempo)
print(componentes[0:20])
## [[-2.68420713  0.32660731]
##  [-2.71539062 -0.16955685]
##  [-2.88981954 -0.13734561]
##  [-2.7464372  -0.31112432]
##  [-2.72859298  0.33392456]
##  [-2.27989736  0.74778271]
##  [-2.82089068 -0.08210451]
##  [-2.62648199  0.17040535]
##  [-2.88795857 -0.57079803]
##  [-2.67384469 -0.1066917 ]
##  [-2.50652679  0.65193501]
##  [-2.61314272  0.02152063]
##  [-2.78743398 -0.22774019]
##  [-3.22520045 -0.50327991]
##  [-2.64354322  1.1861949 ]
##  [-2.38386932  1.34475434]
##  [-2.6225262   0.81808967]
##  [-2.64832273  0.31913667]
##  [-2.19907796  0.87924409]
##  [-2.58734619  0.52047364]]
print(iris.shape)
## (150, 5)
print(componentes.shape)
# Gráfico
## (150, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(iris_tempo))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()

# Graficos de barras de los clusters

colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y  = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
plt.show()

plt.close()
# RADAR PLOT para interpretar
# ===========================

df = pd.DataFrame()
for i in range(iris.shape[1]):
    df = pd.concat([df,pd.DataFrame({iris.columns[i]:centros_trans[i,:].tolist()})],axis = 1)

df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)

# Variables y Número de Variables
##    s.largo  s.ancho  p.largo  p.ancho   tipo      grupo
## 0    6.525    6.525    8.475    8.875  7.375  Cluster-1
## 1    7.700    9.475    7.625    7.750  6.750  Cluster-2
## 2    5.500    6.250    6.500    6.250  8.850  Cluster-3
variables=list(df)[0:5]
variables
## ['s.largo', 's.ancho', 'p.largo', 'p.ancho', 'tipo']
N = len(variables)
print(N)
 
# Ángulo de los ejes 
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
 
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
 
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
 
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables,rotation=45)
 
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
 
# Plotea cada cluster (grupo) = una línea de datos
 
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
 
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()
# Ejemplo 4. Ejemplo con datos Servicio al Cliente
#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploClientesCorregidaEdad.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
##                 Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## Nombre Cliente                       ...                                     
##  Ariana             2.5           1  ...                7.0               6.6
##  Guiselle           2.4           0  ...                9.8               5.4
##  Francisco          2.8           7  ...                9.6               8.5
##  Griselda           2.3           0  ...                2.8               5.4
##  Damaris            4.9           6  ...                2.6               3.3
##  Johana             3.2           4  ...                4.2               7.2
##  Bernal             2.6           0  ...                9.6               6.5
##  Freddy             2.3           4  ...                5.6               4.5
##  Estafania          2.5           4  ...                6.0               7.6
##  Laura              2.9           0  ...                8.4               6.5
##  Arnoldo            3.2          13  ...                7.0               3.9
##  Beatriz            2.7           5  ...                7.6               5.4
##  Rebeca             2.2           0  ...                9.4               4.6
##  Sofia              3.1           5  ...                8.8               2.4
##  Ingrid             2.7           5  ...                7.4               4.0
##  Rocio              4.2           4  ...                5.2               5.7
##  Karen              4.3           5  ...                8.0               5.4
##  Luis               2.4           4  ...                8.0               8.8
##  Pedro              2.1           1  ...                9.6               6.0
##  Lorena             3.0           4  ...                4.6               4.5
##  Elena              3.1           5  ...                8.4               5.6
##  Julian             4.0           5  ...                5.0               1.5
##  Natalie            3.4           1  ...                9.6               4.6
##  Shirley            2.4           0  ...                5.2               3.0
##  Andres             3.8           3  ...                6.4               6.9
##  Alejandro          2.6           6  ...                6.6               3.2
##  Grace              2.8           0  ...                5.8               5.5
##  Nuria              2.1           0  ...                7.4               2.3
##  Flor               2.4           1  ...                6.6               2.5
##  Roberto            4.1           8  ...                6.6               3.2
##  Victor             2.7           3  ...                8.2               5.2
##  Arturo             3.4           5  ...                8.2               6.5
##  Maritza            2.4           4  ...                8.2               5.8
##  Diana              2.4           1  ...                6.4               2.6
##  Juan               2.3           4  ...                4.6               8.1
##  Guillermo          1.9           1  ...                8.8               4.8
##  Silvia             2.5           2  ...                8.6               5.5
## 
## [37 rows x 12 columns]
datos.head()
##                 Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## Nombre Cliente                       ...                                     
##  Ariana             2.5           1  ...                7.0               6.6
##  Guiselle           2.4           0  ...                9.8               5.4
##  Francisco          2.8           7  ...                9.6               8.5
##  Griselda           2.3           0  ...                2.8               5.4
##  Damaris            4.9           6  ...                2.6               3.3
## 
## [5 rows x 12 columns]
datos.shape
## (37, 12)
datos.dropna().describe()

# Ejecuta k-medias con 3 clusters
##          Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## count  37.000000    37.00000  ...          37.000000         37.000000
## mean    2.881081     3.27027  ...           7.075676          5.108108
## std     0.707436     2.83479  ...           1.920851          1.816648
## min     1.900000     0.00000  ...           2.600000          1.500000
## 25%     2.400000     1.00000  ...           5.800000          3.900000
## 50%     2.700000     4.00000  ...           7.400000          5.400000
## 75%     3.200000     5.00000  ...           8.400000          6.500000
## max     4.900000    13.00000  ...           9.800000          8.800000
## 
## [8 rows x 12 columns]
kmedias = KMeans(n_clusters=3)
kmedias.fit(datos)
## KMeans(n_clusters=3)
print(kmedias.predict(datos))
## [1 1 2 0 0 0 1 2 0 1 2 2 1 2 2 2 2 2 1 0 2 0 0 0 0 2 0 1 1 2 1 2 2 0 0 1 1]
centros = np.array(kmedias.cluster_centers_)
centros

# Codo de Jambu 
## array([[3.08333333, 2.66666667, 5.33333333, 7.33333333, 4.33333333,
##         9.66666667, 2.00833333, 9.35      , 5.6       , 5.68333333,
##         5.26666667, 5.01666667],
##        [2.39090909, 0.81818182, 6.34545455, 8.32727273, 8.23636364,
##         9.7       , 4.45454545, 9.18181818, 7.4       , 7.4       ,
##         8.49090909, 5.08181818],
##        [3.09285714, 5.71428571, 6.61428571, 8.04285714, 7.08571429,
##         9.57857143, 3.71428571, 8.55714286, 7.05714286, 7.41428571,
##         7.51428571, 5.20714286]])
Nc = range(1, 20)
kmediasList = [KMeans(n_clusters=i) for i in Nc]
varianza = [kmediasList[i].fit(datos).score(datos) for i in range(len(kmediasList))]
plt.plot(Nc,varianza,'o-')
plt.xlabel('Número de clústeres')
plt.ylabel('Varianza explicada por cada cluster (Inercia Interclases)')
plt.title('Codo de Jambu')
plt.show()

Nc = range(1, 20)
kmediasList = [KMeans(n_clusters=i) for i in Nc]
varianza = [kmediasList[i].fit(datos).inertia_ for i in range(len(kmediasList))]
plt.plot(Nc,varianza,'o-')
plt.xlabel('Número de clústeres')
plt.ylabel('Varianza explicada por cada cluster (Inercia Interclases)')
plt.title('Codo de Jambu')
plt.show()

# En este caso no hay mucha claridad, K=3 o K=7 son buenas opciones

# LOS TRES JUNTOS
colores_1 = ['#C4F6C2','#03864B', '#AF960F','#F124A3','#FEF61E','#10855C',
             '#441308','#4C19BE','#E74D50','#45DC46','#AA27B6','#2B757E']

#plt.figure(1,figsize=(26,20))
# Plotea Centro 1
plt.subplot(3, 1, 1)
y  = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
null =plt.tick_params(labelbottom=False)   
# Plotea Centro 2
plt.subplot(3, 1, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
null =plt.tick_params(labelbottom=False)
# Plotea Centro 3
plt.subplot(3, 1, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns,rotation=30,fontsize=5)
plt.show()

# RADAR PLOT para interpretar
# ===========================

datos
##                 Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## Nombre Cliente                       ...                                     
##  Ariana             2.5           1  ...                7.0               6.6
##  Guiselle           2.4           0  ...                9.8               5.4
##  Francisco          2.8           7  ...                9.6               8.5
##  Griselda           2.3           0  ...                2.8               5.4
##  Damaris            4.9           6  ...                2.6               3.3
##  Johana             3.2           4  ...                4.2               7.2
##  Bernal             2.6           0  ...                9.6               6.5
##  Freddy             2.3           4  ...                5.6               4.5
##  Estafania          2.5           4  ...                6.0               7.6
##  Laura              2.9           0  ...                8.4               6.5
##  Arnoldo            3.2          13  ...                7.0               3.9
##  Beatriz            2.7           5  ...                7.6               5.4
##  Rebeca             2.2           0  ...                9.4               4.6
##  Sofia              3.1           5  ...                8.8               2.4
##  Ingrid             2.7           5  ...                7.4               4.0
##  Rocio              4.2           4  ...                5.2               5.7
##  Karen              4.3           5  ...                8.0               5.4
##  Luis               2.4           4  ...                8.0               8.8
##  Pedro              2.1           1  ...                9.6               6.0
##  Lorena             3.0           4  ...                4.6               4.5
##  Elena              3.1           5  ...                8.4               5.6
##  Julian             4.0           5  ...                5.0               1.5
##  Natalie            3.4           1  ...                9.6               4.6
##  Shirley            2.4           0  ...                5.2               3.0
##  Andres             3.8           3  ...                6.4               6.9
##  Alejandro          2.6           6  ...                6.6               3.2
##  Grace              2.8           0  ...                5.8               5.5
##  Nuria              2.1           0  ...                7.4               2.3
##  Flor               2.4           1  ...                6.6               2.5
##  Roberto            4.1           8  ...                6.6               3.2
##  Victor             2.7           3  ...                8.2               5.2
##  Arturo             3.4           5  ...                8.2               6.5
##  Maritza            2.4           4  ...                8.2               5.8
##  Diana              2.4           1  ...                6.4               2.6
##  Juan               2.3           4  ...                4.6               8.1
##  Guillermo          1.9           1  ...                8.8               4.8
##  Silvia             2.5           2  ...                8.6               5.5
## 
## [37 rows x 12 columns]
centros
## array([[3.08333333, 2.66666667, 5.33333333, 7.33333333, 4.33333333,
##         9.66666667, 2.00833333, 9.35      , 5.6       , 5.68333333,
##         5.26666667, 5.01666667],
##        [2.39090909, 0.81818182, 6.34545455, 8.32727273, 8.23636364,
##         9.7       , 4.45454545, 9.18181818, 7.4       , 7.4       ,
##         8.49090909, 5.08181818],
##        [3.09285714, 5.71428571, 6.61428571, 8.04285714, 7.08571429,
##         9.57857143, 3.71428571, 8.55714286, 7.05714286, 7.41428571,
##         7.51428571, 5.20714286]])
centros_trans = centros.T
centros_trans
## array([[3.08333333, 2.39090909, 3.09285714],
##        [2.66666667, 0.81818182, 5.71428571],
##        [5.33333333, 6.34545455, 6.61428571],
##        [7.33333333, 8.32727273, 8.04285714],
##        [4.33333333, 8.23636364, 7.08571429],
##        [9.66666667, 9.7       , 9.57857143],
##        [2.00833333, 4.45454545, 3.71428571],
##        [9.35      , 9.18181818, 8.55714286],
##        [5.6       , 7.4       , 7.05714286],
##        [5.68333333, 7.4       , 7.41428571],
##        [5.26666667, 8.49090909, 7.51428571],
##        [5.01666667, 5.08181818, 5.20714286]])
df = pd.DataFrame()
for i in range(datos.shape[1]):
    df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)

df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)

# Variables y Número de Variables
##     Edad/10  Antiguedad  ...  Calidad Servicio      grupo
## 0  3.083333    2.666667  ...          5.016667  Cluster-1
## 1  2.390909    0.818182  ...          5.081818  Cluster-2
## 2  3.092857    5.714286  ...          5.207143  Cluster-3
## 
## [3 rows x 13 columns]
variables = list(df)[0:12]
variables
## ['Edad/10', 'Antiguedad', 'Espacios Parqueo', 'Velocidad Cajas', 'Distribucion Productos', 'Atencion Empleados', 'Calidad Instalaciones', 'Ubicacion', 'Limpieza', 'Variedad Productos', 'Prestigio Empresa', 'Calidad Servicio']
N = len(variables)
print(N)
 
# Ángulo de los ejes 
## 12
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
 
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
 
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
 
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
 
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
 
# Plotea cada cluster (grupo) = una línea de datos
 
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
 
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()
# Los dibuja sobre el plano principal los clusters de k-medias
pca = PCA(n_components=2)
componentes = pca.fit_transform(datos)
componentes
## array([[-2.29713786, -1.0440986 ],
##        [-3.67955322, -1.96190882],
##        [-0.62772032,  4.64231098],
##        [ 1.0132489 , -5.21164881],
##        [ 9.6383012 , -1.77660147],
##        [ 2.69029011, -1.06384576],
##        [-3.33779804, -1.8576653 ],
##        [ 1.25061775,  0.34179433],
##        [ 3.41296888, -1.80612147],
##        [-3.256672  , -1.68846677],
##        [ 5.01277194,  7.55924114],
##        [ 0.45713703,  2.00890385],
##        [-4.31444668, -1.1532299 ],
##        [-0.77814906,  2.71798916],
##        [ 2.03613873,  1.03552109],
##        [ 1.76558006,  0.01137745],
##        [ 1.02227888,  1.59870929],
##        [-3.14165189,  2.88770514],
##        [-5.2959146 ,  0.4575491 ],
##        [ 3.03594357, -0.8969674 ],
##        [-1.40718438,  3.11033148],
##        [ 5.15684301, -1.01284596],
##        [-0.50563026, -2.36536284],
##        [ 0.12202622, -4.53423404],
##        [ 2.63071112, -1.92036543],
##        [ 1.12329306,  2.55134427],
##        [ 1.08623432, -4.6862166 ],
##        [-3.38481021, -1.52501917],
##        [-1.608607  , -0.98540369],
##        [ 1.9931198 ,  4.62767147],
##        [-2.49813693,  1.09450718],
##        [-0.46391975,  2.41542231],
##        [-2.3310668 ,  2.29942888],
##        [ 1.05653443, -3.86688064],
##        [ 2.9049432 , -0.67917184],
##        [-4.12791536, -0.60456319],
##        [-4.35266784,  1.28081056]])
print(datos.shape)
## (37, 12)
print(componentes.shape)
## (37, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(datos))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()

Método de Agrupación Jerárquica

Para comprender el método se deben analizar sub-criterios que permiten establecer la manera de agrupación de un conjunto de datos.

Agrupación Jerárquica Aglomerativa

Conocido como “Clusterización Jerárquica”, el enfoque aglomerativo o enfoque ascendente considera cada dato (muestra) como si se tratara como un solo clúster y luego se fusionan o aglomeran por pares en forma sucesiva hasta que todos los clústeres se hayan fusionado en uno solo. La agrupación parte de determinado nivel de agrupamiento y criterios que veremos a continuación.

En esta técnica, inicialmente cada punto de datos se considera como un clúster individual. En cada iteración, los grupos similares se fusionan con otros grupos hasta que se forma un grupo o grupos K.

El algoritmo básico de algomeración consiste en:

  1. Calcular la matriz de proximidad
  2. Dejar que cada punto de datos sea un clúster
  3. Repetir: fusionar los dos clústeres más cercanos y actualizar la matriz de proximidad
  4. Hasta que solo quede un único clúster

La operación clave es el cálculo de la proximidad de dos clústeres.

Agrupación Jerárquica Divisiva

En un agrupamiento divisivo (esta vez de arriba hacia abajo), un incia con un solo clúster de todas las muestras sque se va dividiendo recursivamente en dos clústeres (al menos similares) hasta que haya un clúster para cada observación. A la inversa del método anterior.

Esta técnica no se usa tanto que la anterior, se consideran todos los puntos de datos como un único clúster:

  1. En cada iteración, se separan los puntos de datos del clúster que no son similares.
  2. Cada punto de datos que se separa se considera como un clúster individual.
  3. Al final, quedan n grupos.

Se le llama se le llama agrupamiento jerárquico divisiva ya que se hace repetidamente la división hasta obtener n clústeres,

Agrupación Jerárquica.

El objetivo es combinar repetidamente dos clústers cercanos (de nuevo el criterio de distancia es euclidiana por omisión pero podría ser otro acorde al tipo de tipos) en un clúster más grande.

El algoritmo es el siguiente:

  1. Se comienza calculando la distancia entre cada par de puntos de observación y se almacena en una matriz de distancia.
  2. Se coloca cada punto en su propio grupo (inicialmente todos individuales).
  3. Luego se comienza a fusionar los pares de puntos más cercanos con base en las distancias de la matriz de distancia.
  4. Como resultado la cantidad de clústeres disminuye en 1.
  5. Se recompila la distancia entre el nuevo clúster y los antiguos y los almacena en una nueva matriz de distancia.
  6. Se Se repiten los pasos 2 y 3 hasta que todos los clústeres se fusionan en uno solo.

Los métodos de cálculo de distancia permiten 5 tipos de formas algorítmicas.

Enlace completo.

Se calculan las distancias máximas entres clústers antes de la fusión.

Enlace simple

Se calculan las distancias mínima entres elementos de cada clúster antes de la fusión. Permite ubicar valores atípicos.

Enlace promedio

Se calculan la distancia completa pero se usa la distancia media entre los pares del clúster.

Método centroide

Se localiza el centroide de cada clúster y luego se calcula la distancia entre los centroides antes de fucionarlos.

Método Ward

En este método se consideran todos los clústeres y el algoritmo calcula la suma de las distancias cuadradas dentro de los clústeres y las fusiona para minimizarlas.

Desde un punto de vista estadística, el proceso de aglomeración conduce a una reducción de la varianza de cada clúster resultante.

Cúal método usar

La elección del método vinculación depende totalmente cada quien y no hay un método rápido y robusto que siempre dé buenos resultados. Diferentes métodos de vinculación conducen a diferentes clústering.

Criterios de distancia.

Cómo se indicó anteriormente el criterio de “distancia” es habitualmente euclidiana pero se pueden usar otros criterios dependiendo de la caracterizacón de los datos.

Existen al menos 4 que son utilizados los más utilizados.

  1. Distancia euclidiana

Es la distancia ordinaria en línea recta entre dos puntos en el espacio euclidiano. Con esta distancia, el espacio euclidiano se convierte en un espacio métrico.

  1. Distancia Manhatan

Es similar a la euclidiana, con la condición que la distancia se calcula sumando el valor absoluto de la diferencia entre las dimensiones. Por ejemplo, la distancia de Manhattan implica moverse en línea recta, primero a lo lardo de un eje y luego junto con el otro.

  1. Distancia coseno

Toma en cuenta la forma de las variables, más que sus valores. Tiende a asociar observaciones que tienen las mismas variables máxima y mínima, independientemente de su valor efectivo.

Para ejemplizar el método el siguiente segmento de código en Python muestra el contexto de Clusterización Jerárquica.

## Clusterización Jerárquica

# Import the dendrogram function and the ward clustering function from SciPy
from scipy.cluster.hierarchy import dendrogram, ward, single, complete,average,linkage, fcluster
from scipy.spatial.distance import pdist

# f cluster para los centros

# Simulación del clustering jeráquico
mglearn.plots.plot_agglomerative()
plt.show()

plt.close()

Dendogramas

Es la forma de gráfico que permite observar las agrupaciones resultantes.

En los siguientes segmentos de código se muestran los diferentes métodos de agrupamiento.

# Ejemplo 1. Datos simulados con dos variables 
X, y = make_blobs(random_state=0, n_samples=20, n_features = 3)
X = pd.DataFrame(X).abs()
X.columns = ["X1","X2","X3"]
print(X)
##           X1        X2         X3
## 0   0.180614  0.131432   4.705366
## 1   1.146194  1.558149   2.778408
## 2   2.432693  0.960464   3.067147
## 3   0.409572  4.061638   3.569659
## 4   2.242389  3.797911   4.600468
## 5   1.555621  7.468936  10.392967
## 6   0.643213  4.351152   3.518008
## 7   0.707008  1.078266   1.925452
## 8   1.727676  8.146824   8.497235
## 9   1.706178  8.260853   9.245284
## 10  0.188137  0.887168   2.532019
## 11  0.328146  1.351517   2.455377
## 12  0.121901  0.531193   0.984677
## 13  0.794688  5.713992   1.680796
## 14  2.057082  4.788099   2.634408
## 15  1.009709  4.984355   0.491771
## 16  0.227734  8.482240   8.908921
## 17  1.474195  6.180889   8.633533
## 18  1.927033  7.481832   8.532508
## 19  1.251468  3.343033   2.432194
print(y)

# Agregación de:
## [1 1 1 0 0 2 0 1 2 2 1 1 1 0 0 0 2 2 2 0]
ward_res = ward(X)         #Ward
single_res = single(X)     #Salto mínimo
complete_res = complete(X) #Salto Máximo
average_res = average(X)   #Promedio

# Plotea el dendograma
plt.figure(figsize=(13,10))
null=dendrogram(average_res)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(complete_res)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(single_res)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
d = dendrogram(ward_res)

# Agrega cortes con 2 y 3 clústeres
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [15.5, 15.5], '--', c='k')
ax.plot(limites, [5, 5], '--', c='k')

ax.text(limites[1], 15.5, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 5, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()

plt.close()

Gráficos de barras.

Otra forma de observar los resultados es mediante gráficos de barras. Similar a como se observó en la parte de K-medias.

# Gráficos de barras : 
def centroide(num_cluster, datos, clusters):
  ind = clusters == num_cluster
  return(pd.DataFrame(datos[ind].mean()).T)

grupos = fcluster(linkage(pdist(X), method='ward'),3,'distance')
centros = np.array(pd.concat([centroide(1,X,grupos),centroide(2,X,grupos),centroide(3,X,grupos)]))


colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y  = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y= centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
plt.show()

plt.close()

Gráficos de radar

Otra forma de observar los resultados es mediante gráficos radar, de la misma manera que se presentaron los resultados en la parte de K-medias.

# RADAR PLOT para interpretar
# ===========================
centros_trans = centros.T
centros_trans
## array([[1.43640617, 0.8206799 , 0.18061434],
##        [7.67026242, 1.06112633, 0.13143174],
##        [9.03507453, 2.29051355, 4.70536631]])
df = pd.DataFrame()
for i in range(X.shape[1]):
    df = pd.concat([df,pd.DataFrame({X.columns[i]:centros_trans[i,:].tolist()})],axis = 1)

df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)

# Variables y Número de Variables
##          X1        X2        X3      grupo
## 0  1.436406  7.670262  9.035075  Cluster-1
## 1  0.820680  1.061126  2.290514  Cluster-2
## 2  0.180614  0.131432  4.705366  Cluster-3
variables=list(df)[0:3]
variables
## ['X1', 'X2', 'X3']
N = len(variables)
print(N)
 
# Ángulo de los ejes 
## 3
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
 
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
 
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
 
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
 
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
 
# Plotea cada cluster (grupo) = una línea de datos
 
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
 
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()

Clusterización Jerárquica en ejemplo de estudiantes.

# Ejemplo 2. Datos de Estudiantes

#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploEstudiantes.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
##         Matematicas  Ciencias  Espanol  Historia  EdFisica
## Lucia           7.0       6.5      9.2       8.6       8.0
## Pedro           7.5       9.4      7.3       7.0       7.0
## Ines            7.6       9.2      8.0       8.0       7.5
## Luis            5.0       6.5      6.5       7.0       9.0
## Andres          6.0       6.0      7.8       8.9       7.3
## Ana             7.8       9.6      7.7       8.0       6.5
## Carlos          6.3       6.4      8.2       9.0       7.2
## Jose            7.9       9.7      7.5       8.0       6.0
## Sonia           6.0       6.0      6.5       5.5       8.7
## Maria           6.8       7.2      8.7       9.0       7.0
print(datos.head())
##         Matematicas  Ciencias  Espanol  Historia  EdFisica
## Lucia           7.0       6.5      9.2       8.6       8.0
## Pedro           7.5       9.4      7.3       7.0       7.0
## Ines            7.6       9.2      8.0       8.0       7.5
## Luis            5.0       6.5      6.5       7.0       9.0
## Andres          6.0       6.0      7.8       8.9       7.3
print(datos.shape)

# Agregación de:
## (10, 5)
ward_res = ward(datos)         #Ward
single_res = single(datos)     #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos)   #Promedio

# Plotea el dendograma
plt.figure(figsize=(13,10))

null=dendrogram(average_res,labels= datos.index.tolist())
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist())
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist())
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist())

# Agrega cortes con 2 y 3 clústeres
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [7.25, 7.25], '--', c='k')
ax.plot(limites, [4, 4], '--', c='k')

ax.text(limites[1], 7.25, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 4, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()

plt.close()

Gráficos de barras

# Gráficos de barras : 
grupos = fcluster(linkage(pdist(datos), method='ward'),3,'distance')
centros = np.array(pd.concat([centroide(1,datos,grupos),centroide(2,datos,grupos),centroide(3,datos,grupos)]))

colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
# Plotea Centro 1
plt.figure(1,figsize=(18,8))
plt.subplot(1, 3, 1)
y  = centros[:1,:].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)

# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)

# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()

plt.close()

Gráfico tipo radar

# RADAR PLOT para interpretar
# ===========================
centros_trans = centros.T
centros_trans
## array([[7.7  , 5.5  , 6.525],
##        [9.475, 6.25 , 6.525],
##        [7.625, 6.5  , 8.475],
##        [7.75 , 6.25 , 8.875],
##        [6.75 , 8.85 , 7.375]])
df = pd.DataFrame()
for i in range(datos.shape[1]):
    df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)

df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)

# Variables y Número de Variables
##    Matematicas  Ciencias  Espanol  Historia  EdFisica      grupo
## 0        7.700     9.475    7.625     7.750     6.750  Cluster-1
## 1        5.500     6.250    6.500     6.250     8.850  Cluster-2
## 2        6.525     6.525    8.475     8.875     7.375  Cluster-3
variables=list(df)[0:5]
variables
## ['Matematicas', 'Ciencias', 'Espanol', 'Historia', 'EdFisica']
N = len(variables)
print(N)
 
# Ángulo de los ejes 
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
 
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
 
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
 
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
 
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
 
# Plotea cada cluster (grupo) = una línea de datos
 
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
 
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
 
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()
##_______________________________________________________________________________________

Clusterización Jerárquica para ejemplo de flores Iris

datos = pd.read_csv('../Datos/iris.csv',delimiter=';',decimal=".")
datos = datos.iloc[:,:4] #Elimina la variable categorica
print(datos)
##      s.largo  s.ancho  p.largo  p.ancho
## 0        5.1      3.5      1.4      0.2
## 1        4.9      3.0      1.4      0.2
## 2        4.7      3.2      1.3      0.2
## 3        4.6      3.1      1.5      0.2
## 4        5.0      3.6      1.4      0.2
## ..       ...      ...      ...      ...
## 145      6.7      3.0      5.2      2.3
## 146      6.3      2.5      5.0      1.9
## 147      6.5      3.0      5.2      2.0
## 148      6.2      3.4      5.4      2.3
## 149      5.9      3.0      5.1      1.8
## 
## [150 rows x 4 columns]
print(datos.head())
##    s.largo  s.ancho  p.largo  p.ancho
## 0      5.1      3.5      1.4      0.2
## 1      4.9      3.0      1.4      0.2
## 2      4.7      3.2      1.3      0.2
## 3      4.6      3.1      1.5      0.2
## 4      5.0      3.6      1.4      0.2
print(datos.shape)
## (150, 4)
ward_res = ward(datos)         #Ward
single_res = single(datos)     #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos)   #Promedio

null=dendrogram(average_res,labels= datos.index.tolist(),color_threshold=1.9,leaf_rotation=90)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist(),color_threshold=3.5,leaf_rotation=90)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist(),color_threshold=0.7,leaf_rotation=90)
plt.show()

plt.close()

## Agregando cortes en el dendograma
plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist(),color_threshold=8,leaf_rotation=90)

ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [20, 20], '--', c='k')
ax.plot(limites, [8, 8], '--', c='k')

ax.text(limites[1], 20, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 8, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()

plt.close()

Gráfico de barras

grupos = fcluster(linkage(pdist(datos), method='ward'),3,criterion='maxclust')
print(grupos)
## [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
##  3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3 2 2 2 2 3 2 2 2 2
##  2 2 3 3 2 2 2 2 3 2 3 2 3 2 2 3 3 2 2 2 2 2 3 3 2 2 2 3 2 2 2 3 2 2 2 3 2
##  2 3]
centros = np.array(pd.concat([centroide(1,datos,grupos),centroide(2,datos,grupos),centroide(3,datos,grupos)]))
print(centros)
## [[5.006      3.418      1.464      0.244     ]
##  [6.86944444 3.08611111 5.76944444 2.10555556]
##  [5.9203125  2.7515625  4.4203125  1.434375  ]]
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
# Plotea Centro 1
plt.figure(1,figsize=(18,8))
plt.subplot(1, 3, 1)
y  = centros[:1,:].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()

plt.close()

Gráfico tipo radar

##Radar Plot
centros_trans = centros.T
print(centros_trans)
## [[5.006      6.86944444 5.9203125 ]
##  [3.418      3.08611111 2.7515625 ]
##  [1.464      5.76944444 4.4203125 ]
##  [0.244      2.10555556 1.434375  ]]
df = pd.DataFrame()
for i in range(datos.shape[1]):
    df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df =  pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
##     s.largo   s.ancho   p.largo   p.ancho      grupo
## 0  5.006000  3.418000  1.464000  0.244000  Cluster-1
## 1  6.869444  3.086111  5.769444  2.105556  Cluster-2
## 2  5.920312  2.751562  4.420312  1.434375  Cluster-3
variables=list(df)[0:4]
print(variables)
## ['s.largo', 's.ancho', 'p.largo', 'p.ancho']
N = len(variables)
print(N)

## Angulo de ejes
## 4
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
ax = plt.subplot(111, polar=True)
#Eeje a 90 grados
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)

null=plt.xticks(angulos[:-1], variables)
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)

#Graficando cada cluster (grupo) = una línea de datos
#Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)

#Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)

#Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)

#Plot
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()
###_______________________________________________________________________

Clusterización Jerárquica en clientes

datos = pd.read_csv('../Datos/EjemploClientesCorregidaEdad.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
##                 Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## Nombre Cliente                       ...                                     
##  Ariana             2.5           1  ...                7.0               6.6
##  Guiselle           2.4           0  ...                9.8               5.4
##  Francisco          2.8           7  ...                9.6               8.5
##  Griselda           2.3           0  ...                2.8               5.4
##  Damaris            4.9           6  ...                2.6               3.3
##  Johana             3.2           4  ...                4.2               7.2
##  Bernal             2.6           0  ...                9.6               6.5
##  Freddy             2.3           4  ...                5.6               4.5
##  Estafania          2.5           4  ...                6.0               7.6
##  Laura              2.9           0  ...                8.4               6.5
##  Arnoldo            3.2          13  ...                7.0               3.9
##  Beatriz            2.7           5  ...                7.6               5.4
##  Rebeca             2.2           0  ...                9.4               4.6
##  Sofia              3.1           5  ...                8.8               2.4
##  Ingrid             2.7           5  ...                7.4               4.0
##  Rocio              4.2           4  ...                5.2               5.7
##  Karen              4.3           5  ...                8.0               5.4
##  Luis               2.4           4  ...                8.0               8.8
##  Pedro              2.1           1  ...                9.6               6.0
##  Lorena             3.0           4  ...                4.6               4.5
##  Elena              3.1           5  ...                8.4               5.6
##  Julian             4.0           5  ...                5.0               1.5
##  Natalie            3.4           1  ...                9.6               4.6
##  Shirley            2.4           0  ...                5.2               3.0
##  Andres             3.8           3  ...                6.4               6.9
##  Alejandro          2.6           6  ...                6.6               3.2
##  Grace              2.8           0  ...                5.8               5.5
##  Nuria              2.1           0  ...                7.4               2.3
##  Flor               2.4           1  ...                6.6               2.5
##  Roberto            4.1           8  ...                6.6               3.2
##  Victor             2.7           3  ...                8.2               5.2
##  Arturo             3.4           5  ...                8.2               6.5
##  Maritza            2.4           4  ...                8.2               5.8
##  Diana              2.4           1  ...                6.4               2.6
##  Juan               2.3           4  ...                4.6               8.1
##  Guillermo          1.9           1  ...                8.8               4.8
##  Silvia             2.5           2  ...                8.6               5.5
## 
## [37 rows x 12 columns]
print(datos.head())
##                 Edad/10  Antiguedad  ...  Prestigio Empresa  Calidad Servicio
## Nombre Cliente                       ...                                     
##  Ariana             2.5           1  ...                7.0               6.6
##  Guiselle           2.4           0  ...                9.8               5.4
##  Francisco          2.8           7  ...                9.6               8.5
##  Griselda           2.3           0  ...                2.8               5.4
##  Damaris            4.9           6  ...                2.6               3.3
## 
## [5 rows x 12 columns]
print(datos.shape)
## (37, 12)
ward_res = ward(datos)         #Ward
single_res = single(datos)     #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos)   #Promedio

null=dendrogram(average_res,labels= datos.index.tolist(),color_threshold=9.8)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist(),color_threshold=13)
plt.show()

plt.close()

plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist(),color_threshold=6.5)
plt.show()

plt.close()

## Con divisiones
plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist(),color_threshold=15)
  
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [20, 20], '--', c='k')
ax.plot(limites, [15, 15], '--', c='k')
ax.plot(limites, [12.5, 12.5], '--', c='k')

ax.text(limites[1], 20, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 15, ' tres clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 12.5, ' cinco clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()

plt.close()

Gráfico de barras

numero_clusters = 3
grupos = fcluster(linkage(pdist(datos), method='ward'),numero_clusters,criterion='maxclust')
print(grupos)
## [2 2 3 1 1 1 2 1 1 2 3 3 2 3 3 1 3 3 2 1 3 3 1 1 1 3 1 2 2 3 3 3 3 1 1 2 2]
centro_lista = []
centros = np.array(pd.concat([centroide(i+1,datos,grupos) for i in range(numero_clusters)]))
print(centros)
## [[3.03846154 2.69230769 5.44615385 7.38461538 4.69230769 9.69230769
##   2.13846154 9.01538462 5.84615385 5.83076923 5.30769231 5.3       ]
##  [2.36       0.6        6.22       8.34       8.12       9.7
##   4.7        9.16       7.36       7.44       8.52       5.07      ]
##  [3.10714286 5.71428571 6.67142857 8.05714286 7.11428571 9.55714286
##   3.59285714 8.87142857 6.98571429 7.37142857 7.68571429 4.95714286]]
colores_1 = ['#C4F6C2','#F3864B', '#AF960F','#F124A3','#FEF61E','#10855C',
             '#441308','#4C19BE','#E74D50','#45DC46','#AA27B6','#2B757E']
# Otra manera:
plt.figure(1,figsize=(25,20))
for i in range(numero_clusters):
    null=plt.subplot(numero_clusters, 1, i+1)
    min_limit = i
    max_limit = i+1
    y  = centros[min_limit:max_limit,:].tolist()[0]
    null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
    null=null=plt.xticks(range(datos.shape[1]), datos.columns,rotation=30,fontsize=10)
plt.show()

plt.close()

Gráfico tipo radar

## RADAR PLOT
centros_trans = centros.T
print(centros_trans)
## [[3.03846154 2.36       3.10714286]
##  [2.69230769 0.6        5.71428571]
##  [5.44615385 6.22       6.67142857]
##  [7.38461538 8.34       8.05714286]
##  [4.69230769 8.12       7.11428571]
##  [9.69230769 9.7        9.55714286]
##  [2.13846154 4.7        3.59285714]
##  [9.01538462 9.16       8.87142857]
##  [5.84615385 7.36       6.98571429]
##  [5.83076923 7.44       7.37142857]
##  [5.30769231 8.52       7.68571429]
##  [5.3        5.07       4.95714286]]
nombres =  ["Cluster-%i" % (i+1) for i in range(numero_clusters)]
print(nombres)
## ['Cluster-1', 'Cluster-2', 'Cluster-3']
df = pd.DataFrame()
for i in range(datos.shape[1]):
    df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df =  pd.concat([df,pd.DataFrame({'grupo': nombres})],axis = 1)
print(df)
##     Edad/10  Antiguedad  ...  Calidad Servicio      grupo
## 0  3.038462    2.692308  ...          5.300000  Cluster-1
## 1  2.360000    0.600000  ...          5.070000  Cluster-2
## 2  3.107143    5.714286  ...          4.957143  Cluster-3
## 
## [3 rows x 13 columns]
max_limit = df.shape[1] -1
variables=list(df)[0:max_limit]
print(variables)
## ['Edad/10', 'Antiguedad', 'Espacios Parqueo', 'Velocidad Cajas', 'Distribucion Productos', 'Atencion Empleados', 'Calidad Instalaciones', 'Ubicacion', 'Limpieza', 'Variedad Productos', 'Prestigio Empresa', 'Calidad Servicio']
N = len(variables)
print(N)
## 12
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]

ax = plt.subplot(111, polar=True)

ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)

null=null=plt.xticks(angulos[:-1], variables)

ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
## (0.0, 10.0)
for i in range(numero_clusters):
  valores=df.loc[i].drop('grupo').values.flatten().tolist()
  valores += valores[:1]
  ax.plot(angulos, valores, linewidth=1, linestyle='solid', label=nombres[i])
  ax.fill(angulos, valores, 'b', alpha=0.1)

plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()

plt.close()